package org.summerframework.component.upload.fastdfs;

import org.summerframework.component.upload.exception.FastDFSException;
import org.summerframework.component.upload.fastdfs.pool.ConnectionPoolFactory;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.beans.factory.InitializingBean;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

/**
 * FastDFS 模板类
 */
public class FastdfsTemplateImpl implements FastdfsTemplate, InitializingBean {

    private ConnectionPoolFactory connPoolFactory;
    private FastDFSTemplateFactory factory;

    public FastdfsTemplateImpl(FastDFSTemplateFactory factory) {
        this.factory = factory;
    }

    private static final ThreadLocal<TrackerServer> SERVER_THREAD_LOCAL = new ThreadLocal<>();

    public FastDFSTemplateFactory getFactory() {
        return factory;
    }


    protected StorageClient getClient() throws Exception {
        TrackerServer trackerServer = connPoolFactory.getServer();
        SERVER_THREAD_LOCAL.set(trackerServer);
        return new StorageClient(trackerServer, null);
    }

    private NameValuePair[] covMeta(Map<String, String> metaMap) {
        if (MapUtils.isEmpty(metaMap)) {
            return null;
        }

        int size = metaMap.size();
        NameValuePair[] metaArrays = new NameValuePair[size];
        for (String key : metaMap.keySet()) {
            metaArrays[--size] = new NameValuePair(key, metaMap.get(key));
        }
        return metaArrays;
    }

    private void releaseClient() {
        connPoolFactory.releaseConnection(SERVER_THREAD_LOCAL.get());
        SERVER_THREAD_LOCAL.remove();
    }

    @Override
    public UploadResult uploadFileByInputStream(InputStream fileInputStrem, String fileExtName, Map<String, String> metaMap) {
        try {
            return uploadFileByByte(IOUtils.toByteArray(fileInputStrem), fileExtName, metaMap);
        } catch (IOException e) {
            throw new FastDFSException("upload fail");
        }
    }

    @Override
    public UploadResult uploadFileByByte(byte[] fileBytes, String fileExtName, Map<String, String> metaMap) {
        try {
            String[] rest = getClient().upload_file(fileBytes, fileExtName, covMeta(metaMap));
            return new UploadResult(true, rest[0], rest[1]);
        } catch (Exception e) {
            throw new FastDFSException("upload fail", e);
        } finally {
            releaseClient();
        }
    }

    @Override
    public UploadResult uploadFileByPath(String path, Map<String, String> metaMap) {
        try {
            File file = new File(path);
            return uploadFileByByte(FileUtils.readFileToByteArray(file), FilenameUtils.getExtension(path), metaMap);
        } catch (IOException e) {
            throw new FastDFSException("upload fail", e);
        }
    }

    @Override
    public UploadResult uploadFile(Object obj, String fileExtName, Map<String, String> metaMap) {
        if (obj instanceof InputStream) {
            return uploadFileByInputStream((InputStream) obj, fileExtName, metaMap);
        } else if (obj instanceof byte[]) {
            return uploadFileByByte((byte[]) obj, fileExtName, metaMap);
        } else if (obj instanceof String) {
            return uploadFileByPath((String) obj, metaMap);
        } else {
            throw new FastDFSException("support InputStream、byte[]、String， not support" + obj.getClass().getName());
        }
    }

    @Override
    public byte[] downLoadFile(String fileId) {
        UploadResult ur = UploadResult.parseFromFileId(fileId);

        try {
            StorageClient client = getClient();
            return client.download_file(ur.getGroupName(), ur.getFilePath());
        } catch (Exception e) {
            throw new FastDFSException("delete file error", e);
        } finally {
            releaseClient();
        }
    }

    @Override
    public int deleteFile(String fileId) {
        UploadResult ur = UploadResult.parseFromFileId(fileId);

        try {
            StorageClient client = getClient();
            return client.delete_file(ur.getGroupName(), ur.getFilePath());
        } catch (Exception e) {
            throw new FastDFSException("delete file error", e);
        } finally {
            releaseClient();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        if (factory == null) {
            throw new FastDFSException("factory is not null");
        }

        this.connPoolFactory = new ConnectionPoolFactory(factory);
    }
}
